/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file rw_m1.c
 * @brief M1 tag implementation
 */

#include "nci_feature.h"
#if IS_FEATURE_ON(NCI_FEATURE_RW_M1)

#include "rw_tag.h"
#include "rw_int.h"

#define M1_FLAG_4K_SUPPORT 0x10

#define M1_CMD_AUTH_KEY_A 0x60
#define M1_CMD_AUTH_KEY_B 0x61
#define M1_CMD_READ 0x30
#define M1_CMD_WRITE 0xA0

#define M1_RSP_ACK 0x00
#define M1_RSP_LEN_READ 16

#define M1_BYTES_PRE_BLOCK 16
#define M1_BLOCKS_PRE_SECTOR 4
#define M1_BLOCKS_PRE_SECTOR_16 16
#define M1_BYTES_PRE_SECTOR 64

#define M1_4BLOCK_SECTOR_COUNT 32
#define M1_16BLOCK_SECTOR_COUNT 8

#define M1_BLOCKS_OF_1K 64
#define M1_BLOCKS_OF_2K 128
#define M1_BLOCKS_OF_4K 256
#define M1_SECTORS_OF_1K 16
#define M1_BYTES_OF_1K 1024
#define M1_BYTES_OF_2K 2048
#define M1_BYTES_OF_4K 4096
#define M1_MAX_SECTORE_SIZE 40

#define M1_CMD_LEN_AUTH 0x0C
#define M1_CMD_LEN_READ 0x02
#define M1_CMD_LEN_WRITE 0x12

#define M1_TLV_NULL 0x00
#define M1_TLV_LOCK 0x01
#define M1_TLV_MEM 0x02
#define M1_TLV_NDEF 0x03
#define M1_TLV_PROP 0xFD
#define M1_TLV_TERM 0xFE

#define M1_SHORT_LENGTH_SIZE 0x01
#define M1_LONG_LENGTH_SIZE 0x03

#define M1_NDEF_MAX_SIZE_1K 716
#define M1_NDEF_MAX_SIZE_2K 1436
#define M1_NDEF_MAX_SIZE_4K 3356

#define M1_UID_LEN 4
#define M1_KEY_LEN 6
#define M1_ACCESS_PERMISSION_LEN 4

#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

const static uint8_t s_m1_key_default[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const static uint8_t s_m1_key_mad[] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5};
const static uint8_t s_m1_key_ndef[] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};

const static uint8_t s_access_permission_ndef[] = {0x7F, 0x07, 0x88, 0x40};
const static uint8_t s_access_permission_mad[] = {0x78, 0x77, 0x88, 0xC1};
const static uint8_t s_mad_b1[] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1,
                             0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
const static uint8_t s_mad_b2[] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1,
                             0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
const static uint8_t s_mad_b64[] = {0xE8, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1,
                              0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
const static uint8_t s_ndef_b0[] = {0x03, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


typedef struct {
    bool is_1k_card;
    uint16_t max_block_num;
    int curr_sector;
    uint8_t uid[M1_UID_LEN];
    bool ndef_sector[M1_MAX_SECTORE_SIZE];
    uint8_t ndef_block_no;
    uint8_t ndef_len_start;
    uint16_t ndef_len;
    uint8_t ndef_value_start;
    uint16_t ndef_max_size;
    uint8_t ndef_first_block[M1_BYTES_PRE_BLOCK];
    bool is_ndef_detected;
} tM1_INFO;

static tM1_INFO s_m1_info;

static tNCI_STATUS m1_send_cmd(tNCI_BUF *cmd, tNCI_BUF **pp_rsp) {
    tNCI_BUF *p_rsp = *pp_rsp;
    if (p_rsp) {
        reset_nci_buf(p_rsp);
    } else {
        p_rsp = alloc_nci_buf(0);
        if (!p_rsp) {
            NFCLOG_E("alloc_nci_buf failed");
            return NCI_STATUS_EXT_ALLOC_FAILED;
        }
    }
    tNCI_STATUS ret = rw_transmit(cmd, p_rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("rw_transmit failed, ret = %d", ret);
    } else if (p_rsp->len == 1 && p_rsp->data[0] != M1_RSP_ACK) {
        NFCLOG_E("received NAK: %02X", p_rsp->data[0]);
        ret = NCI_STATUS_EXT_FAILED;
    }
    if (ret != NCI_STATUS_OK) {
        free_nci_buf(p_rsp);
        p_rsp = NULL;
    }
    *pp_rsp = p_rsp;
    return ret;
}

static uint8_t get_sector_from_block(uint8_t block) {
    if (block < M1_BLOCKS_OF_2K) {
        return block / M1_BLOCKS_PRE_SECTOR;
    } else {
        return M1_4BLOCK_SECTOR_COUNT + ((block - M1_BLOCKS_OF_2K) / M1_BLOCKS_PRE_SECTOR_16);
    }
}

static tNCI_STATUS m1_auth(uint8_t block, const uint8_t *p_key, bool use_key_a, tNCI_BUF **pp_rsp) {
    tNCI_BUF *cmd = alloc_nci_buf_with_cap(0, M1_CMD_LEN_AUTH);
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (!cmd) {
        NFCLOG_E("alloc_nci_buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    UINT8_TO_BUF(cmd, use_key_a ? M1_CMD_AUTH_KEY_A : M1_CMD_AUTH_KEY_B);
    UINT8_TO_BUF(cmd, block);
    ARRAY_TO_BUF(cmd, s_m1_info.uid, M1_UID_LEN);
    if (!p_key) {
        if ((block >= 0 && block < M1_BLOCKS_PRE_SECTOR) || (block >= M1_BLOCKS_OF_1K && block < (M1_BLOCKS_OF_1K + M1_BLOCKS_PRE_SECTOR))) {
            p_key = s_m1_key_mad;
        } else {
            p_key = s_m1_key_ndef;
        }
    }
    ARRAY_TO_BUF(cmd, p_key, M1_KEY_LEN);
    ret = m1_send_cmd(cmd, pp_rsp);
    if (ret == NCI_STATUS_OK) {
        s_m1_info.curr_sector = get_sector_from_block(block);
        NFCLOG_I("auth success, sector = %d", s_m1_info.curr_sector);
    } else {
        NFCLOG_E("auth failed, ret = %d", ret);
    }
cleanup:
    free_nci_buf(cmd);
    return ret;
}

static tNCI_STATUS m1_read(uint8_t block, tNCI_BUF **pp_rsp) {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    uint8_t sector = get_sector_from_block(block);
    tM1_INFO *p_m1 = &s_m1_info;
    tNCI_BUF *cmd = NULL;
    if (p_m1->curr_sector != sector) {
        // 当前扇区未经过认证,需要先进行认证
        ret = m1_auth(block, NULL, true, pp_rsp);
        if (ret != NCI_STATUS_OK) {
            goto cleanup;
        }
    }
    cmd = alloc_nci_buf_with_cap(0, M1_CMD_LEN_READ);
    if (!cmd) {
        NFCLOG_E("alloc_nci_buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    UINT8_TO_BUF(cmd, M1_CMD_READ);
    UINT8_TO_BUF(cmd, block);
    ret = m1_send_cmd(cmd, pp_rsp);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }
    tNCI_BUF *rsp = *pp_rsp;
    if (rsp->len != M1_RSP_LEN_READ) {
        NFCLOG_E("rsp len = %d != %d", rsp->len, M1_RSP_LEN_READ);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }
cleanup:
    free_nci_buf(cmd);
    return ret;
}

static tNCI_STATUS m1_write(uint8_t block, uint8_t *p_dat, const uint8_t *p_key, tNCI_BUF **pp_rsp) {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tM1_INFO *p_m1 = &s_m1_info;
    tNCI_BUF *cmd = NULL;
    uint8_t sector = get_sector_from_block(block);
    if (p_m1->curr_sector != sector) {
        // 当前扇区未经过认证,需要先进行认证
        ret = m1_auth(block, p_key, true, pp_rsp);
        if (ret != NCI_STATUS_OK) {
            goto cleanup;
        }
    }
    cmd = alloc_nci_buf_with_cap(0, M1_CMD_LEN_WRITE);
    if (!cmd) {
        NFCLOG_E("alloc_nci_buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    UINT8_TO_BUF(cmd, M1_CMD_WRITE);
    UINT8_TO_BUF(cmd, block);
    ARRAY_TO_BUF(cmd, p_dat, M1_BYTES_PRE_BLOCK);
    ret = m1_send_cmd(cmd, pp_rsp);
cleanup:
    free_nci_buf(cmd);
    return ret;
}

static tNCI_STATUS parse_mad(uint8_t *p_mad_data, uint8_t block) {
    uint8_t start_position = 1;
    uint8_t start_block = 0;
    switch (block) {
        case 1:
            start_position = 1;
            start_block = 0;
            break;
        case 2:
            start_position = 0;
            start_block = 8;
            break;
        case 64:
            start_position = 1;
            start_block = 16;
            break;
        case 65:
            start_position = 0;
            start_block = 24;
            break;
        case 66:
            start_position = 0;
            start_block = 32;
            break;
        default:
            NFCLOG_E("block = %d not support", block);
            return NCI_STATUS_EXT_FAILED;
    }
    tM1_INFO *p_m1 = &s_m1_info;
    uint8_t max = M1_BYTES_PRE_BLOCK / 2;
    for (uint8_t i = start_position; i < max; i++) {
        if ((p_mad_data[2 * i] == 0x03) && (p_mad_data[2 * i + 1] == 0xE1)) {
            p_m1->ndef_sector[i + start_block] = true;
        }
    }
    return NCI_STATUS_OK;
}

static tNCI_STATUS decode_ndef_tlv(tNCI_BUF **pp_rsp) {
    /**
     * 读取第一个NDEF Block，解析其中的NDEF TLV，获取NDEF长度和起始位置
     *
     * 只会读取一个NDEF Block，如果NDEF数据不在第一个Block中，则返回失败
     */
    tM1_INFO *p_m1 = &s_m1_info;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    uint8_t first_block = 0;
    for (uint8_t i = 0; i < M1_MAX_SECTORE_SIZE; i++) {
        if (p_m1->ndef_sector[i]) {
            first_block = i * M1_BLOCKS_PRE_SECTOR;
            break;
        }
    }

    if (first_block == 0) {
        NFCLOG_E("no ndef sector found");
        return NCI_STATUS_EXT_FAILED;
    }

    ret = m1_read(first_block, pp_rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("read ndef sector failed, ret = %d", ret);
        return ret;
    }

    tNCI_BUF *rsp = *pp_rsp;
    uint8_t *p_data = rsp->data;
    uint8_t i = 0;
    while (i < M1_BYTES_PRE_BLOCK) {
        if (p_data[i] == M1_TLV_NULL) {
            i++;
            continue;
        } else if (p_data[i] == M1_TLV_NDEF) {
            break;
        } else {
            NFCLOG_E("unknown tlv type: 0x%02X", p_data[i]);
            return NCI_STATUS_EXT_FAILED;
        }
    }
    if (!osi_memcpy_s(p_m1->ndef_first_block, M1_BYTES_PRE_BLOCK, p_data, M1_BYTES_PRE_BLOCK)) {
        NFCLOG_E("copy ndef first block failed");
        return NCI_STATUS_EXT_COPY_FAILED;
    }
    if ((i + 1) >= M1_BYTES_PRE_BLOCK) {
        NFCLOG_E("decode ndef length failed, i = %d", i);
        return NCI_STATUS_EXT_FAILED;
    }

    if (p_data[i + 1] == 0xFF) {
        if ((i + 3) >= M1_BYTES_PRE_BLOCK) {
            NFCLOG_E("decode ndef length failed, i = %d", i);
            return NCI_STATUS_EXT_FAILED;
        }
        p_m1->ndef_len = (uint16_t)(p_data[i + 2] << 8) | p_data[i + 3];
        p_m1->ndef_value_start = i + 1 + M1_LONG_LENGTH_SIZE;
    } else {
        p_m1->ndef_len = p_data[i + 1];
        p_m1->ndef_value_start = i + 1 + M1_SHORT_LENGTH_SIZE;
    }
    p_m1->ndef_len_start = i + 1;
    p_m1->ndef_block_no = first_block;

    return NCI_STATUS_OK;
}

static tNCI_STATUS ndef_detect(tNCI_RW_NDEF_INFO *p_ndef_info) {
    /**
     * M1卡NDEF检测流程:
     * 1.读取block1,2，解析MAD数据
     * 2.如果支持4K读取block64,65,66，解析MAD数据
     * 3.解析NDEF TLV，获取NDEF长度和起始位置
     */
    tM1_INFO *p_m1 = &s_m1_info;
    tNCI_BUF *rsp = NULL;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    uint8_t mad_blocks[] = {1, 2, 64, 65, 66};
    uint8_t mad_blocks_size = p_m1->is_1k_card ? 2 : 5;
    for (uint8_t i = 0; i < mad_blocks_size; i++) {
        uint8_t curr_block = mad_blocks[i];
        ret = m1_read(curr_block, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("check mad(%d) failed, ret = %d", curr_block, ret);
            goto cleanup;
        }
        ret = parse_mad(rsp->data, curr_block);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("parse mad(%d) failed, ret = %d", curr_block, ret);
            goto cleanup;
        }
    }

    ret = decode_ndef_tlv(&rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("decode ndef tlv failed, ret = %d", ret);
        goto cleanup;
    }

    p_m1->is_ndef_detected = true;

    p_ndef_info->curr_size = p_m1->ndef_len;
    p_ndef_info->max_size = p_m1->ndef_max_size;
    p_ndef_info->mode = NCI_RW_NDEF_MODE_READ_WRITE;

cleanup:
    free_nci_buf(rsp);
    return ret;
}

static int find_next_ndef_block(uint8_t curr_block) {
    tM1_INFO *p_m1 = &s_m1_info;
    uint8_t blocks_pre_sector = (curr_block >= M1_BLOCKS_OF_2K) ? M1_BLOCKS_PRE_SECTOR_16 : M1_BLOCKS_PRE_SECTOR;
    uint8_t block_index_in_sector = curr_block % blocks_pre_sector;
    if (block_index_in_sector < (blocks_pre_sector - 2)) {
        // next block is in the same sector
        return curr_block + 1;
    }

    uint8_t next_sector = (curr_block / blocks_pre_sector) + 1;
    if (next_sector >= M1_4BLOCK_SECTOR_COUNT) {
        blocks_pre_sector = M1_BLOCKS_PRE_SECTOR_16;
    }

    for (uint8_t i = next_sector; i < M1_MAX_SECTORE_SIZE; i++) {
        if (p_m1->ndef_sector[i]) {
            if (i < M1_4BLOCK_SECTOR_COUNT) {
                return i * M1_BLOCKS_PRE_SECTOR;
            } else {
                return M1_BLOCKS_OF_2K + ((i - M1_4BLOCK_SECTOR_COUNT) * M1_BLOCKS_PRE_SECTOR_16);
            }
        }
    }
    return -1;
}

static tNCI_STATUS ndef_read(tNCI_RSP *p_rsp) {
    tM1_INFO *p_m1 = &s_m1_info;
    if (!p_m1->is_ndef_detected) {
        NFCLOG_E("NDEF detection not performed yet");
        return NCI_STATUS_EXT_FAILED;
    }

    uint16_t ndef_len = p_m1->ndef_len;
    if (ndef_len == 0) {
        NFCLOG_E("NDEF length is 0");
        return NCI_STATUS_EXT_EMPTY_DATA;
    }

    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *rsp = NULL;

    p_rsp->data = osi_calloc(ndef_len);
    if (!p_rsp->data) {
        NFCLOG_E("malloc ndef data failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }

    uint8_t offset_in_block = p_m1->ndef_value_start;
    uint8_t curr_block = p_m1->ndef_block_no;

    while (p_rsp->len < ndef_len) {
        ret = m1_read(curr_block, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("read block(%d) failed, ret = %d", curr_block, ret);
            goto cleanup;
        }
        uint8_t copy_len = M1_BYTES_PRE_BLOCK - offset_in_block;
        uint16_t remain_len = ndef_len - p_rsp->len;
        if (copy_len > remain_len) {
            copy_len = remain_len;
        }
        if (!osi_memcpy_s(p_rsp->data + p_rsp->len, ndef_len - p_rsp->len, rsp->data + offset_in_block, copy_len)) {
            NFCLOG_E("copy data failed");
            goto cleanup;
        }
        p_rsp->len += copy_len;
        if (p_rsp->len >= ndef_len) {
            break;
        }
        offset_in_block = 0;
        int next_block_no = find_next_ndef_block(curr_block);
        if (next_block_no <= 0 || next_block_no > 0xFF) {
            NFCLOG_E("find next ndef block failed, next block = %d", next_block_no);
            ret = NCI_STATUS_EXT_FAILED;
            goto cleanup;
        }
        curr_block = (uint8_t) next_block_no;
    }

    if (p_rsp->len != ndef_len) {
        NFCLOG_E("read len(%d) not equal to ndef len(%d)", p_rsp->len, ndef_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

cleanup:
    if (ret != NCI_STATUS_OK) {
        if (p_rsp->data) {
            free(p_rsp->data);
        }
        p_rsp->data = NULL;
        p_rsp->len = 0;
    }
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS ndef_write(uint8_t *p_data, uint32_t data_len) {
    /**
     * NDEF 数据写入流程：
     * 1. 检查是否已经执行过NDEF detect
     * 2. 判断写入数据长度是否大于NDEF最大长度
     * 3. 准备要写入的数据
     * 4. 循环写入数据
     */
    tM1_INFO *p_m1 = &s_m1_info;
    if (!p_m1->is_ndef_detected) {
        NFCLOG_E("NDEF detection not performed yet");
        return NCI_STATUS_EXT_FAILED;
    }

    if (data_len > p_m1->ndef_max_size) {
        NFCLOG_E("data len(%d) is larger than ndef max size(%d)", data_len, p_m1->ndef_max_size);
        return NCI_STATUS_EXT_FAILED;
    }
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *rsp = NULL;
    uint8_t *p_ndef = NULL;
    uint8_t length_size = M1_SHORT_LENGTH_SIZE;
    if (data_len >= 0xFF) {
        length_size = M1_LONG_LENGTH_SIZE;
    }
    uint16_t ndef_len = p_m1->ndef_len_start + length_size + data_len; // NDEF Length之前的数据长度 + NDEF Length + NDEF数据
    if (data_len < p_m1->ndef_max_size) {
        // 只有在写入的数据长度小于NDEF最大长度时，需要添加TLV结束符0xFE，当数据长度等于NDEF最大长度时不再添加TLV结束符0xFE
        ndef_len += 1; // 加上TLV结束符0xFE的长度
    }
    uint8_t padding_len = 0;
    if (ndef_len % M1_BYTES_PRE_BLOCK) {
        // 计算需要填充的字节数，保证数据长度为M1_BYTES_PRE_BLOCK的整数倍
        padding_len = M1_BYTES_PRE_BLOCK - (ndef_len % M1_BYTES_PRE_BLOCK);
        ndef_len += padding_len;
    }
    p_ndef = osi_calloc(ndef_len);
    if (!p_ndef) {
        NFCLOG_E("malloc ndef data failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    if (!osi_memcpy_s(p_ndef, ndef_len, p_m1->ndef_first_block, p_m1->ndef_len_start)) {
        NFCLOG_E("copy ndef first block failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    if (length_size == M1_LONG_LENGTH_SIZE) {
        p_ndef[p_m1->ndef_len_start] = 0xFF;
        p_ndef[p_m1->ndef_len_start + 1] = data_len >> 8;
        p_ndef[p_m1->ndef_len_start + 2] = data_len & 0xFF;
    } else {
        p_ndef[p_m1->ndef_len_start] = data_len & 0xFF;
    }
    if (!osi_memcpy_s(p_ndef + p_m1->ndef_len_start + length_size, ndef_len - (p_m1->ndef_len_start + length_size), p_data, data_len)) {
        NFCLOG_E("copy ndef data failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    if (data_len < p_m1->ndef_max_size) {
        p_ndef[ndef_len - padding_len - 1] = M1_TLV_TERM;
    }

    uint16_t write_len = 0;
    uint8_t block_no = p_m1->ndef_block_no;

    while (write_len < ndef_len) {
        // 没一轮循环写入最多一个block的数据
        uint16_t remain_len = ndef_len - write_len;
        uint8_t curr_write_len = (remain_len > M1_BYTES_PRE_BLOCK) ? M1_BYTES_PRE_BLOCK : remain_len;
        ret = m1_write(block_no, p_ndef + write_len, s_m1_key_ndef, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("m1 write failed, ret = %d", ret);
            goto cleanup;
        }
        write_len += curr_write_len;
        if (write_len >= ndef_len) {
            break;
        }
        int next_block_no = find_next_ndef_block(block_no);
        if (next_block_no <= 0 || next_block_no > 0xFF) {
            NFCLOG_E("find next ndef block failed, block_no = %d", next_block_no);
            ret = NCI_STATUS_EXT_FAILED;
            goto cleanup;
        }
        block_no = (uint8_t) next_block_no;
    }
    if (write_len != ndef_len) {
        NFCLOG_E("write ndef data failed, write len = %d, ndef_len=%d", write_len, ndef_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }
    p_m1->ndef_value_start = p_m1->ndef_len_start + length_size;
    p_m1->ndef_len = data_len;
cleanup:
    if (p_ndef) {
        osi_free(p_ndef);
    }
    free_nci_buf(rsp);
    return ret;
}

/**
 * @brief 根据当前block号准备格式化需要写入的数据
 */
static void prepare_format_data(uint8_t block, uint8_t *p_dat) {
    /**
     * 1: MAD1数据
     * 2,65,66: MAD2数据
     * 3,7: MAD秘钥和访问权限
     * 4: 空的NDEF数据
     * 64: MAD64数据
     * 其他扇区的秘钥Block写入NDEF秘钥和访问权限
     */
    switch (block) {
        case 1:
            ARRAY_TO_STREAM_BE(p_dat, s_mad_b1, M1_BYTES_PRE_BLOCK);
            break;
        case 2:
        case 65:
        case 66:
            ARRAY_TO_STREAM_BE(p_dat, s_mad_b2, M1_BYTES_PRE_BLOCK);
            break;
        case 3:
        case 67:
            ARRAY_TO_STREAM_BE(p_dat, s_m1_key_mad, M1_KEY_LEN);
            ARRAY_TO_STREAM_BE(p_dat, s_access_permission_mad, M1_ACCESS_PERMISSION_LEN);
            ARRAY_TO_STREAM_BE(p_dat, s_m1_key_default, M1_KEY_LEN);
            break;
        case 4:
            ARRAY_TO_STREAM_BE(p_dat, s_ndef_b0, M1_BYTES_PRE_BLOCK);
            break;
        case 64:
            ARRAY_TO_STREAM_BE(p_dat, s_mad_b64, M1_BYTES_PRE_BLOCK);
            break;
        default:
            ARRAY_TO_STREAM_BE(p_dat, s_m1_key_ndef, M1_KEY_LEN);
            ARRAY_TO_STREAM_BE(p_dat, s_access_permission_ndef, M1_ACCESS_PERMISSION_LEN);
            ARRAY_TO_STREAM_BE(p_dat, s_m1_key_default, M1_KEY_LEN);
            break;
    }
}

/**
 * @brief 根据当前block号找到下一个需要格式化的block
 */
static uint8_t find_next_format_block(uint8_t block) {
    /**
     * 1-2,64-66 block写入MAD数据
     * 3,67 block写入MAD秘钥和访问权限
     * 4 block写入空的NDEF数据
     * 其他扇区的秘钥Block写入NDEF秘钥和访问权限
     */
    if (block < 4) {
        return block + 1;
    } else if (block == 4) {
        return 7;
    } else if (block >= 63 && block < 67) {
        return block + 1;
    } else if (block < 127) {
        return block + M1_BLOCKS_PRE_SECTOR;
    } else {
        return block + M1_BLOCKS_PRE_SECTOR_16;
    }
}

static tNCI_STATUS is_ndef_formatable() {
    // 所有M1卡都支持NDEF格式化
    return NCI_STATUS_OK;
}

static tNCI_STATUS ndef_format() {
    /**
     * NDEF Format流程：
     * 1. 为1,2,64,65,66 block写入MAD数据
     * 2. 为3,67 block写入MAD秘钥和访问权限
     * 3. 为4 block写入空的NDEF数据
     * 4. 为其他扇区的秘钥Block写入NDEF秘钥和访问权限
     */
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tM1_INFO *p_m1 = &s_m1_info;
    tNCI_BUF *rsp = NULL;
    uint8_t block_no = 1;
    uint8_t write_buf[M1_BYTES_PRE_BLOCK] = {0};

    while (block_no < p_m1->max_block_num) {
        prepare_format_data(block_no, write_buf);
        ret = m1_write(block_no, write_buf, s_m1_key_default, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("write block(%d) failed, ret = %d", block_no, ret);
            goto cleanup;
        }
        block_no = find_next_format_block(block_no);
    }

    NFCLOG_I("format ndef success");
cleanup:
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS on_select() {
    s_m1_info.curr_sector = -1;
    return NCI_STATUS_OK;
}

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)


static tNCI_STATUS on_conenct(tNCI_RW_TAG *p_tag) {
    (void) p_tag;
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    if (!osi_memset_s(&s_m1_info, sizeof(s_m1_info), 0, sizeof(s_m1_info))) {
        NFCLOG_E("osi_memset_s failed");
        return NCI_STATUS_EXT_FAILED;
    }
    if (!osi_memcpy_s(s_m1_info.uid, M1_UID_LEN, p_tag->uid, M1_UID_LEN)) {
        NFCLOG_E("copy uid failed");
        return NCI_STATUS_EXT_FAILED;
    }
    uint8_t sak = p_tag->tech_params->pa.sel_res;
    uint16_t ndef_max_size = 0;
    uint16_t max_block_num = 0;
    if (sak == 0x08) {
        // 1K卡
        ndef_max_size = M1_NDEF_MAX_SIZE_1K;
        max_block_num = M1_BLOCKS_OF_1K;
        s_m1_info.is_1k_card = true;
    } else if (sak == 0x19) {
        // 2K卡
        ndef_max_size = M1_NDEF_MAX_SIZE_2K;
        max_block_num = M1_BLOCKS_OF_2K;
    } else if (sak == 0x18) {
        // 4K卡
        ndef_max_size = M1_NDEF_MAX_SIZE_4K;
        max_block_num = M1_BLOCKS_OF_4K;
    }
    s_m1_info.max_block_num = max_block_num;
    s_m1_info.ndef_max_size = ndef_max_size;
    s_m1_info.curr_sector = -1;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    return NCI_STATUS_OK;
}

static tNCI_STATUS on_disconnect() {
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    if (!osi_memset_s(&s_m1_info, sizeof(s_m1_info), 0, sizeof(s_m1_info))) {
        NFCLOG_E("osi_memset_s failed");
        return NCI_STATUS_EXT_FAILED;
    }
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    return NCI_STATUS_OK;
}

static tNCI_STATUS check_transceive_resp(uint8_t *p_rsp, uint16_t *p_rsp_len) {
    if (!p_rsp || !p_rsp_len || *p_rsp_len == 0) {
        NFCLOG_E("invalid param");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    uint16_t rsp_len = *p_rsp_len;
    if (rsp_len == 1 && p_rsp[0] != M1_RSP_ACK) {
        NFCLOG_E("transceive failed, nak = 0x%02x", p_rsp[0]);
        return NCI_STATUS_EXT_FAILED;
    }
    return NCI_STATUS_OK;
}

tNCI_RW_TAG_API g_rw_m1_api = {
    .max_retry_count = NCI_RW_DEFAULT_MAX_RETRY_COUNT,
    .on_connect = on_conenct,
    .on_disconnect = on_disconnect,
    .check_transceive_resp = check_transceive_resp,
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    .on_select = on_select,
    .ndef_detect = ndef_detect,
    .ndef_read = ndef_read,
    .ndef_write = ndef_write,
    .is_ndef_formatable = is_ndef_formatable,
    .ndef_format = ndef_format,
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
};

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_M1)
